#include "dataline.h"
#include <limits>

namespace STLData{

    bool dataLineElement::operator==(const dataLineElement &other) const {
        switch (fieldData.fieldType) {
            case 'T':
                if (other.fieldData.fieldType != 'T') {
                    return false;
                } else {
                    return (fieldData.valueText == other.fieldData.valueText);
                }
                break;
            case 'R':
                return (fieldData.valueReal == other.fieldData.valueReal);
                break;
            case 'I':
                if (other.fieldData.fieldType=='R') {
                    return (fieldData.valueReal == other.fieldData.valueReal);
                } else {
                    return (fieldData.valueInt == other.fieldData.valueInt);
                }
                break;
            case 'D':
                if (other.fieldData.fieldType=='D') {
                    return (fieldData.valueDate == other.fieldData.valueDate);
                } else {
                    return (fieldData.valueInt == other.fieldData.valueInt);
                }
                break;
            default:
                return false;
                break;
        }
    }

    bool dataLineElement::compType(const dataLineElement &other) const {
        if (fieldData.fieldType==other.fieldData.fieldType) {
            if (fieldData.fieldType == 'T') {
                return (fieldData.stringLength==other.fieldData.stringLength);
            } else {
                return true;
            }
        } else {
            return false;
        }
    }

    bool dataLineElement::operator!=(const dataLineElement &other) const {
        return !(*this == other);
    }

    bool dataLineElement::operator<(const dataLineElement &other) const {
        switch (fieldData.fieldType) {
            case 'T':
                if (other.fieldData.fieldType != 'T') {
                    return false;
                } else {
                    return (fieldData.valueText < other.fieldData.valueText);
                }
                break;
            case 'R':
                return (fieldData.valueReal < other.fieldData.valueReal);
                break;
            case 'I':
                if (other.fieldData.fieldType=='R') {
                    return (fieldData.valueReal < other.fieldData.valueReal);
                } else {
                    return (fieldData.valueInt < other.fieldData.valueInt);
                }
                break;
            default:
                return false;
                break;
        }
    }

    bool dataLineElement::operator>=(const dataLineElement &other) const {
        return !(*this < other);
    }

    bool dataLineElement::operator>(const dataLineElement &other) const {
        switch (fieldData.fieldType) {
            case 'T':
                if (other.fieldData.fieldType != 'T') {
                    return false;
                } else {
                    return (fieldData.valueText > other.fieldData.valueText);
                }
                break;
            case 'R':
                return (fieldData.valueReal > other.fieldData.valueReal);
                break;
            case 'I':
                if (other.fieldData.fieldType=='R') {
                    return (fieldData.valueReal > other.fieldData.valueReal);
                } else {
                    return (fieldData.valueInt > other.fieldData.valueInt);
                }
                break;
            default:
                return false;
                break;
        }
    }

    bool dataLineElement::operator<=(const dataLineElement &other) const {
        return !(*this > other);
    }

    bool dataLine::insert(keyType searchKey, long value) {
        if (hashKey.find(searchKey)!=hashKey.end()) {
            return false;
        } else {
            dataLineElement elemnt;
            elemnt.fieldData.fieldType = 'I';
            elemnt.fieldData.fieldKey = searchKey;
            elemnt = value;
            lineValues.push_back(elemnt);
            maxIndex = static_cast<int>(lineValues.size())-1;
            hashKey.insert(std::pair<keyType,int>(searchKey, maxIndex));
            return true;
        }
    };
    bool dataLine::insert(keyType searchKey, double value) {
        if (hashKey.find(searchKey)!=hashKey.end()) {
            return false;
        } else {
            dataLineElement elemnt;
            elemnt.fieldData.fieldType = 'R';
            elemnt.fieldData.fieldKey = searchKey;
            elemnt = value;
            lineValues.push_back(elemnt);
            maxIndex = static_cast<int>(lineValues.size())-1;
            hashKey.insert(std::pair<keyType, int>(searchKey, maxIndex));
            return true;
        }
    };
    bool dataLine::insert(keyType searchKey, std::string value) {
        if (hashKey.find(searchKey)!=hashKey.end()) {
            return false;
        } else {
            dataLineElement elemnt;
            elemnt.fieldData.fieldType = 'T';
            elemnt.fieldData.fieldKey = searchKey;
            elemnt = value;
            lineValues.push_back(elemnt);
            maxIndex = static_cast<int>(lineValues.size())-1;
            hashKey.insert(std::pair<keyType, int>(searchKey, maxIndex));
            return true;
        }
    };

    bool dataLine::insert(keyType searchKey, Date value) {
        if (hashKey.find(searchKey)!=hashKey.end()) {
            return false;
        } else {
            dataLineElement elemnt;
            elemnt.fieldData.fieldType = 'D';
            elemnt.fieldData.fieldKey = searchKey;
            elemnt = value;
            lineValues.push_back(elemnt);
            maxIndex = static_cast<int>(lineValues.size())-1;
            hashKey.insert(std::pair<keyType, int>(searchKey, maxIndex));
            return true;
        }
    };

    bool dataLine::createField(keyType searchKey, char fieldType, int length) {
        if (hashKey.find(searchKey)!=hashKey.end()) {
            return false;
        } else {
            dataLineElement elemnt;
            elemnt.fieldData.fieldType = fieldType;
            elemnt.fieldData.fieldKey = searchKey;
            if (fieldType == 'T')
                elemnt.fieldData.stringLength = length;
            else
                elemnt.fieldData.stringLength = 0;
            elemnt.fieldData.valueText = "NaN";
            elemnt.fieldData.valueReal = std::numeric_limits<double>::quiet_NaN();
            elemnt.fieldData.valueInt = std::numeric_limits<long>::min();
            elemnt.fieldData.valueDate = std::numeric_limits<time_t>::min();
            lineValues.push_back(elemnt);
            maxIndex = static_cast<int>(lineValues.size())-1;
            hashKey.insert(std::pair<keyType, int>(searchKey, maxIndex));
            return true;
        }
    };

    bool dataLine::deleteField(keyType searchKey) {

        int indx;
        int i;

        if (hashKey.find(searchKey)!=hashKey.end()) {
            indx = getIndex(searchKey);
            lineValues.erase(lineValues.begin()+indx);
            maxIndex = lineValues.size();
            for (i=indx-1;i<maxIndex;i++) {
                hashKey[lineValues[i].key()] = i;
            }
            return true;
        } else {
            return false;
        }
    };

    dataLine& dataLine::operator=(const dataLine &rhs){
        dataLine::iterator left;
        dataLine::const_iterator right;

        if (this == &rhs) return *this;
        int j = rhs.lineValues.size();
        for (int i = 0; i< maxIndex ; i++) {
            if (i < j) {
                lineValues[i] = rhs.lineValues[i];
            } else {
                break;
            }
        }
        return *this;
    }

    dataLine& dataLine::copyStruct(const dataLine &rhs){
        dataLine::iterator left;
        dataLine::const_iterator right;
        if (this == &rhs) return *this;
        std::map<keyType, int> hash2;
        std::map<keyType, int>::iterator itdel;
        hash2 = hashKey;
        for (itdel=hash2.begin();itdel!=hash2.end();itdel++) {
            deleteField(itdel->first);
        }

        dataLine::const_iterator itnew;
        for (itnew=rhs.begin();itnew!=rhs.end();itnew++) {
            createField(itnew->key(), itnew->type(), itnew->fieldData.stringLength);
        }

        return *this;
    }

    dataLine& dataLine::corresponding(const dataLine &rhs){

        dataLine::const_iterator right;
        for (right = rhs.begin(); right != rhs.end(); right++) {
            if (find((*right).key())!=this->end())
                operator[]((*right).key()) = *right;
        }
        return *this;

    }

    bool dataLine::compStruct(const dataLine & other) {
        for (int i = 0 ;i<static_cast<int>(lineValues.size());i++) {
            if (!(lineValues[i].compType(other.lineValues[i]))) {
                return false;
            }
        }
        return true;
    }
}
